<cite>
**本文档中引用的文件**
- [main.go](file://cmd/execgo/main.go)
- [handler.go](file://internal/api/handler.go)
- [task.go](file://internal/models/task.go)
- [state.go](file://internal/state/state.go)
- [scheduler.go](file://internal/scheduler/scheduler.go)
- [executor.go](file://internal/executor/executor.go)
- [state.json](file://data/state.json)
- [README.md](file://README.md)
</cite>
目录
简介
ExecGo 是一个使用纯 Go 标准库构建的极简 AI 执行引擎,提供任务提交、DAG 调度、并发执行和可观测性的 HTTP 服务。本文档专注于任务管理相关的四个核心 API 端点,详细说明 POST /tasks(提交任务图)、GET /tasks/{id}(获取单个任务)、GET /tasks(列出所有任务)和 DELETE /tasks/{id}(删除任务)的完整规范。
项目结构
ExecGo 采用清晰的分层架构设计,主要组件包括:
graph TB
subgraph "应用入口"
Main[cmd/execgo/main.go<br/>程序入口]
end
subgraph "API 层"
API[internal/api/handler.go<br/>HTTP API 处理器]
end
subgraph "业务逻辑层"
Scheduler[internal/scheduler/scheduler.go<br/>DAG 调度器]
State[internal/state/state.go<br/>状态管理器]
Executor[internal/executor/executor.go<br/>执行器接口]
end
subgraph "数据模型"
Models[internal/models/task.go<br/>任务数据模型]
end
subgraph "持久化"
Data[data/state.json<br/>状态文件]
end
Main --> API
API --> Scheduler
API --> State
Scheduler --> State
Scheduler --> Executor
API --> Models
State --> Data
图表来源
- main.go:1-105
- handler.go:1-157
- scheduler.go:1-231
- state.go:1-180
- executor.go:1-68
- task.go:1-149
章节来源
- main.go:1-105
- README.md:149-177
核心组件
任务状态管理
系统支持五种任务状态,每种状态都有明确的含义和转换规则:
stateDiagram-v2
[*] --> pending
pending --> running : "调度器启动"
running --> success : "执行成功"
running --> failed : "执行失败"
running --> skipped : "依赖失败"
success --> [*]
failed --> [*]
skipped --> [*]
note right of pending : "等待执行<br/>初始状态"
note right of running : "正在执行<br/>执行器处理中"
note right of success : "执行完成<br/>结果可用"
note right of failed : "执行失败<br/>错误信息可用"
note right of skipped : "被跳过<br/>由于依赖失败"
图表来源
- task.go:10-19
任务数据模型
任务对象包含以下核心字段:
| 字段名 | 类型 | 必填 | 描述 |
|---|---|---|---|
| id | string | 是 | 任务唯一标识符 |
| type | string | 是 | 执行器类型(http/shell/file) |
| params | json.RawMessage | 否 | 执行器特定参数 |
| depends_on | []string | 否 | 依赖的任务ID列表 |
| retry | int | 否 | 重试次数(默认0) |
| timeout | int64 | 否 | 超时时间(毫秒) |
| status | TaskStatus | 是 | 当前任务状态 |
| result | json.RawMessage | 否 | 执行结果 |
| error | string | 否 | 错误信息 |
| created_at | time.Time | 是 | 创建时间 |
| updated_at | time.Time | 是 | 更新时间 |
章节来源
- task.go:21-34
架构概览
ExecGo 的任务管理架构采用事件驱动的设计模式:
sequenceDiagram
participant Client as "客户端"
participant API as "API 层"
participant Scheduler as "调度器"
participant State as "状态管理"
participant Executor as "执行器"
Client->>API : POST /tasks (提交任务图)
API->>API : 解析 JSON 请求体
API->>API : 验证任务图合法性
API->>Scheduler : Submit(任务图)
Scheduler->>State : Put(任务状态)
Scheduler->>Scheduler : 构建依赖图
Scheduler->>Scheduler : 入队无依赖任务
loop 任务执行循环
Scheduler->>State : UpdateStatus(运行中)
Scheduler->>Executor : Execute(任务)
Executor-->>Scheduler : 执行结果
Scheduler->>State : UpdateStatus(成功/失败)
Scheduler->>Scheduler : 触发下游任务
end
Client->>API : GET /tasks/{id}
API->>State : Get(任务ID)
State-->>API : 任务详情
API-->>Client : 200 OK + 任务数据
Client->>API : GET /tasks
API->>State : GetAll()
State-->>API : 任务列表
API-->>Client : 200 OK + 任务数组
Client->>API : DELETE /tasks/{id}
API->>State : Delete(任务ID)
State-->>API : 删除结果
API-->>Client : 204 No Content 或 404 Not Found
图表来源
- handler.go:58-126
- scheduler.go:69-97
- state.go:55-92
详细组件分析
POST /tasks - 提交任务图
端点规范
- 方法: POST
- 路径:
/tasks - 内容类型:
application/json - 认证: 无(开放访问)
请求体格式
任务图必须包含一个 tasks 数组,每个任务对象遵循以下结构:
{
"tasks": [
{
"id": "string",
"type": "http | shell | file",
"params": {
"url": "https://example.com",
"method": "GET",
"headers": {},
"body": {}
},
"depends_on": ["task1", "task2"],
"retry": 3,
"timeout": 5000
}
]
}
请求验证规则
- 任务图不能为空: 至少包含一个任务
- 任务ID要求: 每个任务必须有唯一的非空ID
- 类型验证: 任务类型必须存在且在执行器注册表中
- 依赖验证:
- 依赖的任务必须存在于图中
- 不能依赖自身
- 不能形成循环依赖
- 重复ID检查: ID 在整个任务图中必须唯一
成功响应
- 状态码: 202 Accepted
- 响应体: 包含接受的任务数量和任务ID列表
{
"accepted": 3,
"task_ids": ["task1", "task2", "task3"]
}
错误响应
- 400 Bad Request: 请求格式无效或验证失败
- 400 Bad Request: 未知任务类型
- 400 Bad Request: 任务图验证失败
常见使用场景
- 单任务提交: 提交简单的单一任务
- DAG 工作流: 提交复杂的多任务依赖图
- 批量任务: 一次性提交多个相互独立的任务
章节来源
- handler.go:58-99
- task.go:41-79
GET /tasks/{id} - 获取单个任务
端点规范
- 方法: GET
- 路径:
/tasks/{id} - 路径参数:
id- 任务唯一标识符 - 内容类型:
application/json - 认证: 无
成功响应
- 状态码: 200 OK
- 响应体: 完整的任务对象
{
"id": "fetch-data",
"type": "http",
"params": {
"url": "https://httpbin.org/json",
"method": "GET"
},
"depends_on": [],
"retry": 0,
"timeout": 10000,
"status": "success",
"result": {
"slideshow": {
"title": "Sample Slide Show"
}
},
"created_at": "2026-01-01T12:00:00Z",
"updated_at": "2026-01-01T12:00:05Z"
}
错误响应
- 404 Not Found: 任务不存在
最佳实践
- 幂等性: GET 请求是幂等的,可以安全重试
- 轮询策略: 建议使用指数退避策略进行状态轮询
- 错误处理: 始终检查响应状态码
章节来源
- handler.go:101-110
- state.go:62-68
GET /tasks - 列出所有任务
端点规范
- 方法: GET
- 路径:
/tasks - 内容类型:
application/json - 认证: 无
成功响应
- 状态码: 200 OK
- 响应体: 任务对象数组
[
{
"id": "step1",
"type": "file",
"params": {
"action": "write",
"path": "data/test.txt",
"content": "Hello from ExecGo DAG!"
},
"timeout": 3000,
"status": "success",
"result": {
"bytes_written": 22
},
"created_at": "2026-03-25T11:41:12.1617732+08:00",
"updated_at": "2026-03-25T11:41:12.1629204+08:00"
}
]
最佳实践
- 分页处理: 对于大量任务,建议实现分页机制
- 过滤策略: 可以在客户端实现按状态或类型过滤
- 缓存策略: 对于频繁查询的场景,可以实现本地缓存
章节来源
- handler.go:112-116
- state.go:70-80
DELETE /tasks/{id} - 删除任务
端点规范
- 方法: DELETE
- 路径:
/tasks/{id} - 路径参数:
id- 任务唯一标识符 - 内容类型:
application/json - 认证: 无
成功响应
- 状态码: 204 No Content
- 响应体: 无
错误响应
- 404 Not Found: 任务不存在
注意事项
- 不可逆操作: 删除操作是不可逆的
- 依赖影响: 删除上游任务会影响下游任务的执行
- 资源清理: 删除后相关资源会被释放
章节来源
- handler.go:118-126
- state.go:82-92
依赖关系分析
执行器注册机制
系统采用注册表模式管理执行器,支持动态扩展:
classDiagram
class Executor {
<<interface>>
+Type() string
+Execute(ctx, task) json.RawMessage, error
}
class HTTPExecutor {
+Type() string
+Execute(ctx, task) json.RawMessage, error
}
class ShellExecutor {
+Type() string
+Execute(ctx, task) json.RawMessage, error
}
class FileExecutor {
+Type() string
+Execute(ctx, task) json.RawMessage, error
}
class Registry {
-registry map[string]Executor
+Register(Executor)
+Get(string) Executor
+RegisteredTypes() []string
+RegisterBuiltins()
}
Executor <|.. HTTPExecutor
Executor <|.. ShellExecutor
Executor <|.. FileExecutor
Registry --> Executor : "管理"
图表来源
- executor.go:14-67
任务验证流程
任务图验证采用多阶段检查机制:
flowchart TD
Start([开始验证]) --> CheckEmpty["检查任务图是否为空"]
CheckEmpty --> Empty{"为空?"}
Empty --> |是| ReturnEmpty["返回错误: 任务图为空"]
Empty --> |否| CheckID["验证每个任务ID"]
CheckID --> IDValid{"ID有效?"}
IDValid --> |否| ReturnID["返回错误: ID无效"]
IDValid --> |是| CheckType["验证任务类型"]
CheckType --> TypeValid{"类型有效?"}
TypeValid --> |否| ReturnType["返回错误: 未知类型"]
TypeValid --> |是| CheckDuplicate["检查重复ID"]
CheckDuplicate --> Duplicate{"有重复?"}
Duplicate --> |是| ReturnDup["返回错误: 重复ID"]
Duplicate --> |否| CheckDepends["验证依赖关系"]
CheckDepends --> DepValid{"依赖有效?"}
DepValid --> |否| ReturnDep["返回错误: 依赖无效"]
DepValid --> |是| CheckCycle["检测循环依赖"]
CheckCycle --> Cycle{"有环?"}
Cycle --> |是| ReturnCycle["返回错误: 循环依赖"]
Cycle --> |否| Success["验证通过"]
图表来源
- task.go:41-79
- task.go:81-121
章节来源
- executor.go:31-67
- task.go:41-121
性能考虑
并发控制
系统采用信号量机制控制最大并发执行数:
- 默认并发限制: 10
- 可配置: 通过命令行参数调整
- 动态调整: 支持运行时配置
内存管理
- 状态存储: 使用
sync.RWMutex保证并发安全 - 内存优化: 采用延迟加载和定期持久化策略
- 垃圾回收: 通过上下文取消机制及时释放资源
网络性能
- 超时设置: 默认读取超时15秒,写入超时30秒
- 连接复用: 使用标准库 HTTP 客户端自动复用连接
- 优雅关闭: 支持平滑关闭,确保资源正确释放
故障排除指南
常见错误及解决方案
| 错误类型 | 状态码 | 错误原因 | 解决方案 |
|---|---|---|---|
| JSON解析错误 | 400 | 请求体不是有效的JSON | 检查JSON格式,使用在线验证工具 |
| 验证失败 | 400 | 任务图不符合规范 | 检查任务ID、类型、依赖关系 |
| 未知类型 | 400 | 执行器未注册 | 确认任务类型是否正确 |
| 任务不存在 | 404 | ID不存在 | 检查任务ID是否正确 |
| 资源不足 | 503 | 并发达到上限 | 减少并发数或等待任务完成 |
调试技巧
- 启用调试日志: 查看系统日志了解详细错误信息
- 健康检查: 使用
/health端点确认服务状态 - 指标监控: 通过
/metrics端点查看系统指标 - 状态持久化: 检查
data/state.json文件确认状态
性能优化建议
- 批量提交: 将相关任务合并为单个请求
- 合理重试: 设置适当的重试次数和超时时间
- 依赖优化: 合理设计任务依赖关系,避免不必要的串行
- 资源管理: 及时清理已完成的任务
章节来源
- handler.go:64-85
- scheduler.go:127-190
结论
ExecGo 的任务管理 API 提供了简洁而强大的功能,支持复杂的工作流编排和状态管理。通过清晰的分层架构和严格的验证机制,系统能够可靠地处理各种任务场景。
主要优势
- 简单易用: RESTful API 设计直观,易于理解和使用
- 功能完整: 支持完整的任务生命周期管理
- 可扩展性: 基于注册表的执行器架构便于扩展
- 可靠性: 完善的错误处理和状态持久化机制
- 可观测性: 丰富的日志和指标支持
最佳实践总结
- 任务设计: 合理设计任务粒度,避免过细或过粗
- 依赖管理: 明确任务间的依赖关系,避免循环依赖
- 错误处理: 实现完善的错误处理和重试机制
- 监控告警: 建立监控体系,及时发现和解决问题
- 资源管理: 合理配置并发和资源,避免系统过载
通过遵循本文档的规范和最佳实践,开发者可以充分利用 ExecGo 的能力构建高效可靠的 AI 任务执行系统。